/*
 * Copyright (C) 2012, 2013 by Ralph Germ, Martin Budden, Arne Kesting, Martin Treiber
 * <ralph.germ@gmail.com>
 * -----------------------------------------------------------------------------------------
 * 
 * This file is part of
 * 
 * MovSimDroid.
 * 
 * MovSimDroid is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * MovSimDroid is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with MovSim. If not, see <http://www.gnu.org/licenses/>
 * or <http://www.movsim.org>.
 * 
 * -----------------------------------------------------------------------------------------
 * 
 *
 * * @file MovSimDroidActivity.java
 * @author Gwen Nellen and Raul Barrera, (c) July 15, 2013
 * @description MovSimDroid handles level presentation and control,
 *              gameplay, and results transmission/storage
 * @note Contains custom SendScoreAsyncTask for asynchronously sending local
 *      results from user device to remote database     
 * -----------------------------------------------------------------------------------------     
 */
package org.movsim.movdroid;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.log4j.Level;
import org.movsim.input.ProjectMetaData;
import org.movsim.movdroid.graphics.MovSimTrafficView;
import org.movsim.movdroid.util.FormatUtil;
import org.movsim.movdroid.util.OnFirstBoot;
import org.movsim.simulator.SimulationRun;
import org.movsim.simulator.SimulationRunnable;
import org.movsim.simulator.Simulator;
import org.movsim.simulator.roadnetwork.RoadNetwork;
import org.movsim.simulator.roadnetwork.VariableMessageSignBase;
import org.movsim.simulator.roadnetwork.VariableMessageSignDiversion;
import org.movsim.utilities.Units;

import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.widget.Toast;
import android.view.Window;

import com.actionbarsherlock.app.ActionBar.OnNavigationListener;
import org.movsim.movdroid.DatabaseHandler;

import android.view.Menu;
import android.view.MenuItem;
import android.view.SubMenu;

import de.mindpipe.android.logging.log4j.LogConfigurator;

public class MovSimDroidActivity extends Activity implements OnNavigationListener,
        SimulationRun.CompletionCallback, SimulationRunnable.UpdateStatusCallback {
	
	private Context context = this;
	int red, yellow, green = -1;

    // MovSim core uses slf4j as a logging facade for log4j.
    static {
        final LogConfigurator logConfigurator = new LogConfigurator();

        logConfigurator.setUseFileAppender(false);
        logConfigurator.setUseLogCatAppender(true);
        // logConfigurator.setFileName(Environment.getExternalStorageDirectory() + "myapp.log");
        logConfigurator.setRootLevel(Level.INFO);
        // Set log level of a specific logger
        logConfigurator.setLevel("org.apache", Level.INFO);
        logConfigurator.configure();
    }

    private ProjectMetaData projectMetaData;
    private Simulator simulator;
    private SimulationRunnable simulationRunnable;

    private VariableMessageSignBase variableMessageSign = new VariableMessageSignDiversion();
    private MovSimTrafficView trafficView;
    private Menu menu;
    private RoadNetwork roadNetwork;
    private Resources res;
    private String projectName;
    private String projectPath;
    private MovSimActionBar movsimActionBar;
    private int navigationItemPosition;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
		try{
        super.onCreate(savedInstanceState);
        res = getResources();

        // Used to set 
        Bundle extra = getIntent().getExtras();
        if(extra != null){
        	if(extra.containsKey("config")){
        		extra = extra.getBundle("config");
        		int scen = extra.getInt("choice_Scen");
        		red = (scen == 0) ? extra.getInt("red_light") : -1;
        		yellow = (scen == 0) ? extra.getInt("yellow_light") : -1;
        		green = (scen == 0) ? extra.getInt("green_light") : -1;
        		System.out.println("red = " + red + " : yellow = " + yellow + " : green = "  + green);
        	}
        }
        
        // Replace parser from MovSim. -> Default values from DTD are not set. -> update xml files from MovSim before!
        System.setProperty("org.xml.sax.driver", "org.xmlpull.v1.sax2.Driver");

        setupSimulator();

        movsimActionBar = new MovSimActionBar(this, simulator);

        trafficView = new MovSimTrafficView(this, simulator, projectMetaData);

        setContentView(trafficView);
        if (simulationRunnable != null) {
            simulationRunnable.pause();
        }
        
        // project selection
        projectName = res.getStringArray(R.array.projectName)[2];
        projectPath = res.getStringArray(R.array.projectPath)[2];
        createInputStreams();
        simulator.loadScenarioFromXml(projectName, projectPath);
        simulationRunnable.start();
        simulationRunnable.pause();
        if (projectName.equals("routing")) {
            roadNetwork.setHasVariableMessageSign(true);
        }
        trafficView.resetGraphicproperties();
        trafficView.forceRepaintBackground();

		}catch(Exception E){
    		Toast toast1 = Toast.makeText(getApplicationContext(), E.toString(), Toast.LENGTH_SHORT);
    		toast1.show();
    	}
    }

    private void setupSimulator() {
        projectMetaData = ProjectMetaData.getInstance();

        projectMetaData.setParseFromInputstream(true);
        projectMetaData.setInstantaneousFileOutput(false);

        simulator = new Simulator(projectMetaData);

        simulationRunnable = simulator.getSimulationRunnable();
        simulationRunnable.setCompletionCallback(this);
        simulationRunnable.addUpdateStatusCallback(this);

        roadNetwork = simulator.getRoadNetwork();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        this.menu = menu;
        menu.clear();
        menu.add(res.getString(R.string.start)).setIcon(R.drawable.ic_action_start)
                .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
        menu.add(res.getString(R.string.restart)).setIcon(R.drawable.ic_action_restart)
                .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT);

        menu.add(res.getString(R.string.action)).setIcon(R.drawable.ic_action_trafficlight)
                .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT);

        SubMenu subMenu1 = menu.addSubMenu(R.string.menu);
        //subMenu1.add(res.getString(R.string.faster));
       // subMenu1.add(res.getString(R.string.slower));
        subMenu1.add(res.getString(R.string.info));
        subMenu1.add(res.getString(R.string.movsimInfo));

        MenuItem subMenu1Item = subMenu1.getItem();
        subMenu1Item.setIcon(R.drawable.abs__ic_menu_moreoverflow_holo_dark);
        subMenu1Item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);

        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        movsimActionBar.selectAction(item);
//		Toast toast1 = Toast.makeText(getApplicationContext(), "option "+item.toString(), Toast.LENGTH_SHORT);
//		toast1.show();
        return true;
    }

    @Override
    public boolean onNavigationItemSelected(int itemPosition, long itemId) {
        this.navigationItemPosition = itemPosition;
        if (simulationRunnable != null) {
            simulationRunnable.pause();
        }
        OnFirstBoot.show(this, "start", itemPosition + "start.accepted",
                res.getStringArray(R.array.infoScenario)[itemPosition], res.getString(R.string.onFirstBoot_title));
        // project selection
        projectName = res.getStringArray(R.array.projectName)[itemPosition];
        projectPath = res.getStringArray(R.array.projectPath)[itemPosition];
        createInputStreams();
        simulator.loadScenarioFromXml(projectName, projectPath);
        simulationRunnable.start();
        simulationRunnable.pause();
        if (projectName.equals("routing")) {
            roadNetwork.setHasVariableMessageSign(true);
        }
        trafficView.resetGraphicproperties();
        trafficView.forceRepaintBackground();
        if (menu != null) {
            menu.getItem(0).setIcon(R.drawable.ic_action_start).setTitle(R.string.start);
            
            // Set visibility of interaction button
            if (itemPosition == 0 || itemPosition == 1) {
                menu.getItem(2).setVisible(true);
            } else {
                menu.getItem(2).setVisible(false);
            }
            
        }
        return true;
    }

    void createInputStreams() {
        try {
            String full = projectPath + projectName;
            InputStream movsimXml = getAssets().open(full + ".xml");
            projectMetaData.setMovsimXml(movsimXml);
            InputStream is = getAssets().open(full + ".xodr");
            projectMetaData.setNetworkXml(is);
            InputStream isProp = getAssets().open(full + ".properties");
            projectMetaData.setProjectProperties(isProp);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        onCreateOptionsMenu(menu);

        if (!simulationRunnable.isPaused()) {
            MenuItem item = menu.getItem(0);
            item.setIcon(R.drawable.ic_action_pause);
            item.setTitle(R.string.pause);
        }
    }

    @Override
    public void simulationComplete(final double simulationTime) {
        final double totalVehicleTravelTime = roadNetwork.totalVehicleTravelTime();
        final double totalVehicleTravelDistance = roadNetwork.totalVehicleTravelDistance() * Units.M_TO_KM;
        final double totalVehicleFuelUsedLiters = roadNetwork.totalVehicleFuelUsedLiters();
        final String formatedSimulationDuration = FormatUtil.getFormatedTime(simulationTime);
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                SimulationFinished finished = new SimulationFinished(res, totalVehicleTravelTime,
                        totalVehicleTravelDistance, totalVehicleFuelUsedLiters, formatedSimulationDuration,
                        simulationTime, MovSimDroidActivity.this);
                Score score = new Score( 0,simulationTime, red, yellow, green);
                DatabaseHandler db = new DatabaseHandler(context);
                db.getWritableDatabase();
                System.out.println("------------------ \n added score!! \n ---------");
                db.addScore(score);
                System.out.println("------------------ \n close db!! \n ---------");
                db.close();
                if (NetworkUtil.isNetworkAvailable(context)) {	// if network connection is available
    				doSendResults();	// call transmit handler
    				System.out.println("------------------ \n it sent the results!! \n ---------");
    			}else {	// if network connection unavailable
    				//doNotSendResults();	// call unable-to-transmit handler
    				// do nothing for now... fix this later
    			}
            }
        });
    }

    @Override
    public void updateStatus(double simulationTime) {
        if (simulator.isFinished()) {
            // hack to simulationComplete
            simulationRunnable.setDuration(simulationTime);
        }
    }

    @Override
    protected void onPause() {
        simulationRunnable.pause();
        menu.getItem(0).setIcon(R.drawable.ic_action_start).setTitle(R.string.start);
        super.onPause();
    }

    public void showInfo(String info) {
        Intent intent = new Intent();
        intent.putExtra("message", info);
        intent.setClass(MovSimDroidActivity.this, InfoDialog.class);
        startActivity(intent);
    }

    public VariableMessageSignBase getVariableMessageSign() {
        return variableMessageSign;
    }

    public MovSimTrafficView getMovSimTrafficView() {
        return trafficView;
    }

 // starts the light configuration activity
    public void startConfig(){
    	
    	Intent config = new Intent(MovSimDroidActivity.this,
				TrafficLightConfig.class);
    	config.putExtra("red", red);
    	config.putExtra("yellow", yellow);
    	config.putExtra("green", green);
		startActivityForResult(config, 0);
    }
    
    // retrieves data from light configuration activity
    protected void onActivityResult(int requestCode, int resultCode, Intent data){
    	if(resultCode == RESULT_OK && requestCode == 0){
    		System.out.println("meow meow meow");
    		red = data.getExtras().getInt("red");
    		yellow = data.getExtras().getInt("yellow");
    		green = data.getExtras().getInt("green");
    		trafficView.setLights(red, yellow, green);
    	}
    }
    
    public Menu getMenu() {
        return menu;
    }

    public int getNavigationItemPosition() {
        return navigationItemPosition;
    }

 // handles transmission attempt event
 	private void doSendResults() {
 		//setMessage("Uploading Score...");	// set upload display message
 		SendScoreAsyncTask task = new SendScoreAsyncTask();	// create new SendScoreAsyncTask to transmit results asynchronously
 		task.execute(doSetParams());	// get results to send and execute asynchronous task
 	}
 	
 // handles transmission of local results to remote database asynchronously
 	private class SendScoreAsyncTask extends AsyncTask<ArrayList<NameValuePair>, Void, String> {

 		@Override	// task to do asynchronously
 		protected String doInBackground(ArrayList<NameValuePair>... params) {				
            System.out.println("------------------ \n async doinbackground!! \n ---------");
 			String url = NetworkUtil.SEND_URL;	// URL of remote script to store local results remotely
 			System.out.println("------------------ \n zURL!! "+url+"\n ---------");
 			String response = "";	// initialize String to hold response
 			HttpParams httpParams = new BasicHttpParams();	// create Object to hold Http parameters
 			int timeoutConnection = 5000;	// specify connection timeout in milliseconds
 			int timeoutSocket = 5000;	// specify socket timeout in milliseconds
 			HttpConnectionParams.setConnectionTimeout(httpParams, timeoutConnection); // set connection timeout as specified
 			HttpConnectionParams.setSoTimeout(httpParams, timeoutSocket);	// set socket timeout as specified
 			DefaultHttpClient client = new DefaultHttpClient(httpParams);	// create HttpClient with desired Http parameters (timeouts)
 			HttpPost httpPost = new HttpPost(url);	// use POST method to specified URL
 			try {	// try
                System.out.println("------------------ \n doinbackground try.catch!! \n ---------");
                System.out.println("------------------ \n params:"+params[0]+" \n ---------");
 				httpPost.setEntity(new UrlEncodedFormEntity(params[0]));	// put local results in POST request
 				HttpResponse execute = client.execute(httpPost);	// execute POST request from client
 				InputStream content = execute.getEntity().getContent();	// create InputStream from content
 				BufferedReader buffer = new BufferedReader(new InputStreamReader(content));	// create BufferedReader from InputStream
 				String s = "";	// String to hold response line
 				while ((s = buffer.readLine()) != null) {	// while line exists
 					response += s;	// append line to response
 				}
                System.out.println("------------------ \n trycatch done!! \n ---------");
 			} catch (Exception e) {	// fail
 				e.printStackTrace();	// print stack trace for debugging
 				return null;	// return null response
 			}
            System.out.println("------------------ \n Response"+response+"!! \n ---------");

 			return response;	// return response on success
 		
 		
 	
 		}
 		
 		protected void onPostExecute(String result) {
			if (result == null) {	// if execution failed
				//didNotSendScore();	// call fail handler
				// fix this to do something when score is not sent...
			}
			
			int response = 0;	// initialize response to 0
			try {
				response = Integer.parseInt(result);	// attempt to parse result as integer
			}catch (NumberFormatException e) {}
			System.out.println("response:::" + response);
			if (response != 7) ;// fix to do something... 
				//didNotSendScore();	// if execution failed, call fail handler
		
			else didSendScore();	// if execution successful, call success handler
		}
 	}
 	
 	private void didSendScore() {
		DatabaseHandler db = new DatabaseHandler(this);	// create new DatabaseHandler object
		db.deleteScores();	// clear all rows from yet-to-submit table
		db.close();	// close DatabaseHandler
        System.out.println("------------------ \n sent score *didsendscore*!! \n ---------");

		//mMessageText.setText("Upload Successful!");	// set upload progress display
		//isSending = false;	// disable transmission-in-progress
		//mTrafficLight.setEnabled(true);	// enable traffic light control for replay
	}
 	
	// handles fetching and return of results from not-yet-submitted table and parcels appropriately for transmission
	private ArrayList<NameValuePair> doSetParams() {
        System.out.println("------------------ \n setting params!! \n ---------");
		DatabaseHandler db = new DatabaseHandler(this);	// create new DatabaseHandler object
		String results = db.getSubmitScores();	// get JSONArray String of yet-to-submit results
		ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();	// create new ArrayList of NameValuePairs
		params.add(new BasicNameValuePair("results", results));	// put results to params

        System.out.println("------------------ \n params set!! \n ---------");		
		return params;	// return params
	}


}
